package org.dxy.domain.handler.process;

import com.google.common.eventbus.EventBus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.port.IEventRepository;
import org.dxy.domain.port.IdGenerator;
import org.dxy.domain.port.CommandHandler;
import org.dxy.domain.port.repository.IProcessRepository;
import org.dxy.domain.command.process.CreateProcessCommand;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.model.aggregate.factory.ProcessFactory;
import org.dxy.domain.model.aggregate.Process;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;

/**
 * 创建工序命令处理器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CreateProcessCommandHandler implements CommandHandler<CreateProcessCommand, Long> {

    private final IProcessRepository processRepository;
    private final ProcessFactory processFactory;
    private final EventBus eventBus;
    private final IdGenerator idGenerator;
    private final IEventRepository eventRepository;
    
    @Transactional
    @Override
    public CommandResult<Long> handle(CreateProcessCommand command) {
        try {
            log.info("开始处理创建工序命令: {}", command);
            
            // 1. 生成工序ID
            Long processId = idGenerator.generate();
            
            // 2. 使用工厂创建聚合根（工厂内部会进行业务规则验证）
            Process process = processFactory.create(processId, command);
            
            // 3. 保存聚合根
            processRepository.save(process);

            List<DomainEvent> events = process.getDomainEvents();
            
            // 4. 保存事件到事件存储，获取固定的事件ID列表
            List<Long> eventIds = eventRepository.saveEvents(events);
            
            // 5. 创建事件副本用于发布
            List<DomainEvent> eventsCopy = new ArrayList<>(events);
            
            // 6. 注册事务提交后的事件发布回调
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    // 使用事务提交前保存的事件副本
                    eventsCopy.forEach(eventBus::post);

                    // 当事件发布成功后，会把这个字段标记为 true；（如果系统崩溃或重启，可以扫描未发布的事件（published = false）重新发布，保证"最终一致性"。）
                    eventRepository.markEventsPublished(eventIds);

                    // 7. 清理事件
                    process.clearDomainEvents();
                }
            });

            log.info("工序创建成功, processId={}, command={}", processId, command);
            return CommandResult.success(processId, "工序创建成功");
            
        } catch (Exception e) {
            log.error("工序创建失败", e);
            return CommandResult.fail(null,"工序创建异常");
        }
    }
}